#!/bin/env python3
# -*- coding:utf-8 -*-
"""
    [模块名]
    Add By :e4ting e4ting@qq.com 2024-03-23 10:53:41
"""

from flask_restful import Resource
from flask         import redirect,request,make_response

import sys,os
import json
from copy import copy
from pdb import set_trace as strace
from traceback  import format_exc as dumpstack

import requests as http

from e4ting import util,log
from e4ting.cache import HistoryCache,WXChatCache

class History():
    def __init__(self, uuid):
        self.uuid = uuid

    def append(self, content={}):
        HistoryCache(self.uuid).set(**{HistoryCache.gpt_seq:content})
        return self

    def get(self):
        cache = HistoryCache(self.uuid)
        if not cache.exists():
            return []
        msg = HistoryCache(self.uuid).get()
        if not msg:
            return []
        data = [ (int(k), json.loads(v)) for k,v in msg.items() if k.isalnum()]
        data.sort(key=lambda x:x[0])
        ret = [v for seq,v in data]
        log.debug(ret)
        return ret

class DONE():

    def is_in_chat(self):
        # 是否自动回复
        return not HistoryCache(str(self)).auto_replay in ["stop", "0", None]

    def into_chat(self):
        # 添加自动回复
        HistoryCache(str(self)).auto_replay = "start"

    def quit_chat(self):
        # 退出自动回复
        HistoryCache(str(self)).auto_replay = "stop"

    def switch(self):
        if self.is_in_chat():
            self.quit_chat()
        else:
            self.into_chat()

    def done(self):
        url  = os.environ.get("WEB_CALLBACK").format(**dict(os.environ))
        data = {
            "to": self.to.name,
            "isRoom":False,
            "data": { "content": str(self.replay) }
        }
        http.post(url, json=data)

class WXMsg():
    def __init__(self, msg={}, txt=""):
        self.msg = msg
        self.txt = txt

    def parse_content(self, type):
        if type == "text":
            return self.msg.get("content", '')
        if type == "file":
            file = request.files["content"]
            name = "/tmp/" + file.filename
            log.debug(name)
            file.save(name)
            return name

        return self.msg.get("content", '')

    def init(self):
        self.isSystemEvent = self.msg.get("isSystemEvent", '0')
        self.isMentioned   = self.msg.get("isMentioned", '0')
        self.isMsgFromSelf = self.msg.get("isMsgFromSelf", '0')
        self.type          = self.msg.get("type", 'unknown')
        self.content       = self.parse_content(self.type)
        self.source        = self.msg.get("source", "{}")

        data = json.loads(self.source or "{}")

        self.FROM          = WXUser(data.get("from", {}))
        self.to            = WXUser(data.get("to", {}))
        self.room          = WXRoom(data.get("room", {}))

        WXChatCache("聊天记录").set(**{HistoryCache.gpt_seq:self.msg})
        if self.is_pai1pai():
            self.switch()
        return self

    def switch(self):
        if self.room:
            (self.room + self.FROM).switch()
        else:
            self.FROM.switch()

    def is_pai1pai(self):
        if not self.type in ["unknown"]:
            return False
        if "拍了拍我" in self.content:
            return True
        return False

    def done(self):
        pass

    def __str__(self):
        return self.content

    def __repr__(self):
        room = str(self.room) if self.room else ""
        if self.type == "text":
            return "{room}-[{self.FROM} => {self.to}]: {self.content}".format(self=self, room=room)
        return "{room}-{self.msg}".format(self=self, room=room)

class WXUser(DONE):
    def __init__(self, data={}):
        self.is_init = False
        if data:
            self.init(data.get("payload", {}))

    def init(self, payload={}):
        self.alias = payload.get("alias", "")
        self.name  = payload.get("name", "")
        self.phone = payload.get("phone", "")
        self.type  = payload.get("type", "")
        self.signature = payload.get("signature", "")

        self.is_init = True

    def __bool__(self):
        return self.is_init

    def done(self):
        self.to = self
        super().done()

    def __rrshift__(self, ai):
        # 给这个用户发送消息， 也可能是一个AI
        # log.info(ai)
        self.replay = ai
        return self

    def __str__(self):
        return self.alias or self.name

    def __repr__(self):
        if self.alias:
            return "({self.alias})".format(self=self)
        return "({self.name})".format(self=self)

class WXRoom(WXUser):
    def init(self, payload={}):
        self.alias = payload.get("topic", "")
        self.name  = payload.get("topic", "")
        # self.phone = payload.get("phone", "")
        self.type  = payload.get("type", "")
        self.signature = payload.get("signature", "")

    def __add__(self, other):
        bak = copy(self)
        bak.name = ":".join([bak.name, other.name])
        return bak

class AI(DONE):
    def __init__(self):
        from openai import OpenAI
        import httpx
        self.client = OpenAI(
                api_key=os.environ.get("API_KEY"),
                base_url=os.environ.get("BASE_URL"),
                max_retries=0,
                timeout=httpx.Timeout(60.0, read=50.0, write=10.0, connect=5.0),
            )

    def chat_with_openai(self, user_input="你是谁"):

        prompt = dict(role="user", content=user_input)
        chat_completion = self.client.chat.completions.create(
                                messages=[*self.history.get()[-30:], prompt],
                                model="gpt-3.5-turbo",
                            )
        replays = [ line.message.content for line in chat_completion.choices]
        log.info(replays)
        ret = "".join(replays)

        # 成功回复了的话，就写入历史记录
        self.history.append(prompt)
        self.history.append(dict(role="assistant", content=ret))

        return ret

    def __str__(self):
        #  将消息 发给AI，然后返回

        if os.environ.get("AUTO_REPLAY") in ["stop", "STOP"]:
            log.warn("已终止自动回复！！！" )
            return ""

        if self.msg.room:
            # 如果是群聊，判断这个说话的人是否开了自动回复
            if not (self.msg.room + self.msg.FROM).is_in_chat():
                return ""
        else:
            # 如果是私聊
            if not self.msg.FROM:
                return ""
            if not self.msg.FROM.is_in_chat():
                return ""
        return self.chat_with_openai(str(self.msg))

    def __rrshift__(self, msg):
        # 将消息 发给AI
        self.msg = msg
        # strace()
        if type(self.msg) is str:
            self.history = History('e4ting')
        else:
            self.history = History(str(self.msg.room if self.msg.room else self.msg.FROM))
        # log.info(msg)
        return self

class WebWXBot(Resource):

    def format(self, content):
        if not content:
            return {
                    "success" : False,
                    "data" : ""
                }
        return {
                    "success" : True,
                    "data" : [
                        {
                          "type": "text",
                          "content": str(content)
                        }
                    ]
                }

    def post(self, id=None):
        """ 消息回调 """
        log.info(request.form)
        data = dict(request.form)
        msg = WXMsg(msg=data).init()

        # util.log(msg)
        ai = AI()
        if msg.type == "text":
            # (msg >> ai >> msg.FROM).done()
            msg >> ai
            return self.format(ai)
        else:
            msg.done()
        # ("你好" >> msg.FROM).done()
        return {
            "success" : False,
            "data" : ""
        }

if __name__ == '__main__':
    ai = AI()
    # "你好！你是谁？" >> ai
    # log.info(str(ai))

    "我叫e4ting" >> ai
    log.info(str(ai))

    "你知道我是谁吗？" >> ai
    log.info(str(ai))
